package com.reger.l2cache.pipeline.ops;

import java.util.Set;

import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate;
import org.springframework.data.redis.connection.RedisZSetCommands.Limit;
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.lang.Nullable;

public interface RedisZSetPipeline<K, M> extends RedisKeyPipeline<K> {

	@Nullable
	Boolean zAdd(K key, double score, M value);

	@Nullable
	Long zAdd(K key, Set<Tuple> tuples);

	@Nullable
	Long zRem(K key, @SuppressWarnings("unchecked") M... values);

	@Nullable
	Double zIncrBy(K key, double increment, M value);

	@Nullable
	Long zRank(K key, M value);

	@Nullable
	Long zRevRank(K key, M value);

	@Nullable
	Set<M> zRange(K key, long start, long end);

	@Nullable
	Set<Tuple> zRangeWithScores(K key, long start, long end);

	@Nullable
	default Set<M> zRangeByScore(K key, double min, double max) {
		return zRangeByScore(key, new Range().gte(min).lte(max));
	}

	@Nullable
	default Set<Tuple> zRangeByScoreWithScores(K key, Range range) {
		return zRangeByScoreWithScores(key, range, Limit.unlimited());
	}

	@Nullable
	default Set<Tuple> zRangeByScoreWithScores(K key, double min, double max) {
		return zRangeByScoreWithScores(key, new Range().gte(min).lte(max));
	}

	@Nullable
	default Set<M> zRangeByScore(K key, double min, double max, long offset, long count) {
		return zRangeByScore(key, new Range().gte(min).lte(max),
				new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue()));
	}

	@Nullable
	default Set<Tuple> zRangeByScoreWithScores(K key, double min, double max, long offset, long count) {
		return zRangeByScoreWithScores(key, new Range().gte(min).lte(max),
				new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue()));
	}

	@Nullable
	Set<Tuple> zRangeByScoreWithScores(K key, Range range, Limit limit);

	@Nullable
	Set<M> zRevRange(K key, long start, long end);

	@Nullable
	Set<Tuple> zRevRangeWithScores(K key, long start, long end);

	@Nullable
	default Set<M> zRevRangeByScore(K key, double min, double max) {
		return zRevRangeByScore(key, new Range().gte(min).lte(max));
	}

	@Nullable
	default Set<M> zRevRangeByScore(K key, Range range) {
		return zRevRangeByScore(key, range, Limit.unlimited());
	}

	@Nullable
	default Set<Tuple> zRevRangeByScoreWithScores(K key, double min, double max) {
		return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), Limit.unlimited());
	}

	@Nullable
	default Set<M> zRevRangeByScore(K key, double min, double max, long offset, long count) {
		return zRevRangeByScore(key, new Range().gte(min).lte(max),
				new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue()));
	}

	@Nullable
	Set<M> zRevRangeByScore(K key, Range range, Limit limit);

	@Nullable
	default Set<Tuple> zRevRangeByScoreWithScores(K key, double min, double max, long offset, long count) {
		return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max),
				new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue()));
	}

	@Nullable
	default Set<Tuple> zRevRangeByScoreWithScores(K key, Range range) {
		return zRevRangeByScoreWithScores(key, range, Limit.unlimited());
	}

	@Nullable
	Set<Tuple> zRevRangeByScoreWithScores(K key, Range range, Limit limit);

	@Nullable
	default Long zCount(K key, double min, double max) {
		return zCount(key, new Range().gte(min).lte(max));
	}

	@Nullable
	Long zCount(K key, Range range);

	@Nullable
	Long zCard(K key);

	@Nullable
	Double zScore(K key, M value);

	@Nullable
	Long zRemRange(K key, long start, long end);

	@Nullable
	default Long zRemRangeByScore(K key, double min, double max) {
		return zRemRangeByScore(key, new Range().gte(min).lte(max));
	}

	@Nullable
	Long zRemRangeByScore(K key, Range range);

	@Nullable
	Long zUnionStore(K destKey, @SuppressWarnings("unchecked") K... sets);

	@Nullable
	Long zUnionStore(K destKey, Aggregate aggregate, int[] weights, @SuppressWarnings("unchecked") K... sets);

	@Nullable
	Long zInterStore(K destKey, @SuppressWarnings("unchecked") K... sets);

	@Nullable
	Long zInterStore(K destKey, Aggregate aggregate, int[] weights, @SuppressWarnings("unchecked") K... sets);

	Cursor<Tuple> zScan(K key, ScanOptions options);

	@Nullable
	default Set<M> zRangeByScore(K key, String min, String max) {
		return zRangeByScore(key, new Range().gte(min).lte(max));
	}

	@Nullable
	default Set<M> zRangeByScore(K key, Range range) {
		return zRangeByScore(key, range, Limit.unlimited());
	}

	@Nullable
	Set<M> zRangeByScore(K key, String min, String max, long offset, long count);

	@Nullable
	Set<M> zRangeByScore(K key, Range range, Limit limit);

	@Nullable
	default Set<M> zRangeByLex(K key) {
		return zRangeByLex(key, Range.unbounded());
	}

	@Nullable
	default Set<M> zRangeByLex(K key, Range range) {
		return zRangeByLex(key, range, Limit.unlimited());
	}

	@Nullable
	Set<M> zRangeByLex(K key, Range range, Limit limit);

	default RedisZSetPipeline<K, M> toZsetPl() {
		return this;
	}
}
